#pragma version(1)
#pragma rs java_package_name(com.android.filter)
#include "rs_cl.rsh"
//const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};
int width;
int height;
int num_geo;

bool gaussian_curve_d;
int curve_length;
int curve_array[3];
int curve_sum_array[3];

rs_allocation gIn;
rs_allocation gTmp;
rs_allocation gVertices;
rs_allocation gIndices;

/*const int curve[] = { 154, 255, 154 };
const int curve_d[] = { -154, 0, 154 };
const int curve_sum[] = { 0, 154, 409 };
const int curve_d_sum[] = { 0, -154, -154 };*/

void root(const uchar4 *v_in, uchar *v_out) {
    float4 f4 = convert_float4(v_in[0]);

    uchar vv = (uchar)(0.2989f * f4[0] + 0.5870f * f4[1] + 0.1140f * f4[2]);
    *v_out = vv;//rsPackColorTo8888(mono);
}


/*void gaussianBlur(const uchar *v_in, uchar *v_out, uint32_t x, uint32_t y) {
	const float k1 = 0.1715728f; // w = 2
    const float k2 = 0.0857864f; // w = 1
    const float k3 = 0.0606601f; // w = 1/1.4 = 0.7

    if ((x==0)||(x==width-1)||(y==0)||(y==height-1)) return;

    // elementXY is the element of a 3x3 matrix centered around current sample
    // TODO: learn about rsMatrixMultiply and alike
    const uchar *e11 = rsGetElementAt(gIn, x-1, y-1);
    const uchar *e21 = rsGetElementAt(gIn, x, y-1);
    const uchar *e31 = rsGetElementAt(gIn, x+1, y-1);

    const uchar *e12 = rsGetElementAt(gIn, x-1, y);
    const uchar *e22 = rsGetElementAt(gIn, x, y); 
    const uchar *e32 = rsGetElementAt(gIn, x+1, y);

    const uchar *e13 = rsGetElementAt(gIn, x-1, y+1);
    const uchar *e23 = rsGetElementAt(gIn, x, y+1);
    const uchar *e33 = rsGetElementAt(gIn, x+1, y+1);

    uchar res = (uchar)( *e22 * k1 +
                (*e21 + *e12  + *e32 + *e23) * k2 + 
                (*e11 + *e31  + *e13 + *e33) * k3);

    *v_out = res;
}*/

void gaussianDerivHorizontalPass(const uchar *v_in, uchar *v_out, uint32_t x, uint32_t y) 
{
	int initial_p;
	int initial_m;
	//int posX, posY;
	int total;
	int value = 0;
	int length = 1;
    
    const uchar *te1 = rsGetElementAt(gIn, 0, y);
    initial_p = *te1;
    const uchar *te2 = rsGetElementAt(gIn, width - 1, y);
    initial_m = *te2;
	
	//posY = y - 1;
	if(x == 0)
	{
		const uchar *e2Y = rsGetElementAt(gIn, x, y);
		const uchar *e3Y = rsGetElementAt(gIn, x + 1, y);
		value += initial_p * (curve_sum_array[1] - curve_sum_array[0]);//posY = 0;
		value += *e2Y * curve_array[1] + *e3Y * curve_array[2];
	}
	else if(x == width - 1)
	{
		const uchar *e1Y = rsGetElementAt(gIn, x - 1, y);
		const uchar *e2Y = rsGetElementAt(gIn, x, y);
		value += initial_m * (curve_sum_array[2] + curve_array[1] - curve_sum_array[2]);
		value += *e1Y * curve_array[0] + *e2Y * curve_array[1];
	}
	else
	{
		const uchar *e1Y = rsGetElementAt(gIn, x - 1, y);
		const uchar *e2Y = rsGetElementAt(gIn, x, y);
		const uchar *e3Y = rsGetElementAt(gIn, x + 1, y);
		value = *e1Y * curve_array[0] + *e2Y * curve_array[1] + *e3Y * curve_array[2];
	}
    
    if(!gaussian_curve_d)
    	total = curve_sum_array[2] + curve_array[2];
    else
    	total = curve_sum_array[1] * -2;
    float p = value / (float)total;
    
    if(gaussian_curve_d)
		p += 128;
    
	float horizontal = clamp(p, 0.0f, 255.0f);
    
    *v_out = (uchar)horizontal;
}

void gaussianDerivVerticalPass(const uchar *v_in, uchar *v_out, uint32_t x, uint32_t y) 
{
	int initial_p;
	int initial_m;
	//int posX, posY;
	int total;
	int value = 0;
	int length = 1;
    
	const uchar *te1 = rsGetElementAt(gIn, x, 0);
    initial_p = *te1;
    const uchar *te2 = rsGetElementAt(gIn, x, height - 1);
    initial_m = *te2;
			
	//posY = y - 1;
	if(y == 0)
	{
		const uchar *eX2 = rsGetElementAt(gIn, x, y);
		const uchar *eX3 = rsGetElementAt(gIn, x, y + 1);
		value += initial_p * (curve_sum_array[1] - curve_sum_array[0]);//posY = 0;
		value += *eX2 * curve_array[1] + *eX3 * curve_array[2];
	}
	else if(y == height - 1)
	{
		const uchar *eX1 = rsGetElementAt(gIn, x, y - 1);
		const uchar *eX2 = rsGetElementAt(gIn, x, y);
		value += initial_m * (curve_sum_array[2] + curve_array[1] - curve_sum_array[2]);
		value += *eX1 * curve_array[0] + *eX2 * curve_array[1];
	}
	else
	{
		const uchar *eX1 = rsGetElementAt(gIn, x, y - 1);
		const uchar *eX2 = rsGetElementAt(gIn, x, y);
		const uchar *eX3 = rsGetElementAt(gIn, x, y + 1);
		value = *eX1 * curve_array[0] + *eX2 * curve_array[1] + *eX3 * curve_array[2];
	}
    //posX = x;
	//posY = y;
    //posX = x;
	//posY = y + 1;
	//if(posY < 0)
	//	posY = 0;
	//if(posY > height-1)
	//	posY = height-1;
    
    if(!gaussian_curve_d)
    	total = curve_sum_array[2] + curve_array[2];
    else
    	total = curve_sum_array[1] * -2;
    	
    float p = value / (float)total;
    
    if(gaussian_curve_d)
		p += 128;
    
	float vertical = clamp(p, 0.0f, 255.0f);
    
    *v_out = (uchar)vertical;
}
void gaussianDeriv(const uchar *v_in, uchar *v_out, uint32_t x, uint32_t y) 
{
	const uchar *vertical = rsGetElementAt(gIn, x, y);
 	const uchar *horizontal = rsGetElementAt(gTmp, x, y);
 	float edge = 0.f;
 	if(y == 0 || y == height - 1 || x == 0 || x == width - 1)
	{
		edge = 7.5;
	}
	else
	{
		int hv = *horizontal - 128;
	 	int vv = *vertical - 128;
		edge = (float)sqrt((float)((hv * hv) + (vv * vv)));
	}
 	
    uchar res =  (uchar)clamp(edge, 0.0f, 255.0f);
    
    *v_out = res;
}
void runMosaic(const uchar4 *v_in, uchar4 *v_out)
{
	int i, j, k, l, n, vertexPos;
	n = 0;
	vertexPos = 0;
	//for(l = 0; l < num_geo; l++)
	//{
		const int* index = rsGetElementAt(gIndices, l);
		
		int left, top, right, bottom;
		const int* tv = rsGetElementAt(gVertices, vertexPos + 1);
		bottom = top = *tv;
		for(k = 0; k < *index; k++)
		{
			const int* vertexX = rsGetElementAt(gVertices, vertexPos + k * 2);
			const int* vertexY = rsGetElementAt(gVertices, vertexPos + k * 2 + 1);
			if(*vertexY < top)
				top = *vertexY;
				
			if(*vertexY > bottom)
				bottom = *vertexY;
				
			if(*vertexX < left)
				left = *vertexX;
				
			if(*vertexX > right)
				right = *vertexX;
		}
		float4 color_sum = {0,0,0,0};
		int count = 0;
		for(i = top; i < bottom; i++)
		{
			int startVertexX, startVertexY;
			int xs, ys, xe, ye;
			int startX, endX;
			
			startX = right;
			endX = left;
			for(k = 0; k < *index; k++)
			{
				int tmp;
				if(k == *index - 1)
				{
					const int* txs = rsGetElementAt(gVertices, vertexPos + k * 2);
					const int* tys = rsGetElementAt(gVertices, vertexPos + k * 2 + 1);
					xs = *txs;
					ys = *tys;
					xe = startVertexX;
					xe = startVertexY;
				}
				else
				{
					const int* txs = rsGetElementAt(gVertices, vertexPos + k * 2);
					const int* tys = rsGetElementAt(gVertices, vertexPos + k * 2 + 1);
					const int* txe = rsGetElementAt(gVertices, vertexPos + k * 2 + 2);
					const int* tye = rsGetElementAt(gVertices, vertexPos + k * 2 + 3);
					if(k == 0)
					{
						startVertexX = *txs;
						startVertexY = *tys;
					}
					xs = *txs;
					ys = *tys;
					xe = *txe;
					xe = *tye;
				}
				if (ys > ye)
				{
					tmp = ye; ye = ys; ys = tmp;
					tmp = xe; xe = xs; xs = tmp;
				}
				float xinc = (xe - xs) / (ye - ys);
				float x = xs + (0.5f + (i - top)) * xinc;
				
				if( x < startX)
					startX = x;
				if( x > endX)
					endX = x;
			}
			for(j = startX; j < endX; j++)
			{
				uchar4 u4 = rsGetElementAt_uchar4(gIn, j, i); 
  				float4 f4 = rsUnpackColor8888(u4);
  				color_sum += f4;
  				count++;
			}
		}
		
		//vertexPos = vertexPos + index * 2;
	//}
}